package cn.microservices.cloud.gateway.interpector.ip;

import cn.microservices.cloud.gateway.util.WebFluxUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * IP本地拦截配置
 */
@Component
public class LocalIpInterceptor {
	private final Map<String, AccessRecord> ipIntercept = new ConcurrentHashMap<>(1000);
	private final int ACCESS_FORBIDDEN_TIMES = 300;
	private final int ACCESS_INTERVAL_TIMES = 2000;
	private Logger logger = LoggerFactory.getLogger(getClass());


	/**
	 * 是否允许访问
	 *
	 * @param request 访问请求
	 * @return
	 */
	public boolean isPass(ServerHttpRequest request) {
		//频率限制
		return !isOverRate(request);

	}

	private boolean isOverRate(ServerHttpRequest request) {
		String ip = WebFluxUtil.getRealIp(request);
		if (StringUtils.isEmpty(ip)) {
			logger.warn("空Ip地址正在进行访问......");
			return true;

		} else {
			AccessRecord accessRecord = ipIntercept.get(ip);

			long currentTime = System.currentTimeMillis();

			if (accessRecord == null) {
				accessRecord = new AccessRecord();
				accessRecord.setAccessTimes(0);
				accessRecord.setFirstAccessTime(currentTime);
			}
			long intervalTime = currentTime - accessRecord.getFirstAccessTime();


			if (intervalTime > ACCESS_INTERVAL_TIMES) {
				accessRecord.setAccessTimes(0);
				accessRecord.setFirstAccessTime(currentTime);
			}
			int count = accessRecord.getAccessTimes();

			accessRecord.setAccessTimes(++count);

			ipIntercept.put(ip, accessRecord);


			if (intervalTime < ACCESS_INTERVAL_TIMES && accessRecord.getAccessTimes() > ACCESS_FORBIDDEN_TIMES) {
				logger.warn("ip{} 时间间隔 {} 毫秒 访问路径={}, {} 次 ,已拦截 ", ip, intervalTime, request.getURI(), accessRecord.getAccessTimes());
				return true;

			}


		}
		return false;
	}

	/**
	 * 访问记录
	 */
	private static class AccessRecord {
		/**
		 * 第一次访问时间
		 */
		private long firstAccessTime;

		/**
		 * 访问的次数
		 */
		private int accessTimes;

		public long getFirstAccessTime() {
			return firstAccessTime;
		}

		public void setFirstAccessTime(long firstAccessTime) {
			this.firstAccessTime = firstAccessTime;
		}

		public int getAccessTimes() {
			return accessTimes;
		}

		public void setAccessTimes(int accessTimes) {
			this.accessTimes = accessTimes;
		}

		@Override
		public String toString() {
			return "AccessRecord{" +
				"firstAccessTime=" + firstAccessTime +
				", accessTimes=" + accessTimes +
				'}';
		}
	}

}
